
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <inttypes.h>

#define cpu_serialize() \
	asm volatile("cpuid" : : : "%rax", "%rbx", "%rcx", "%rdx")

static inline unsigned long rdtsc(void)
{
	unsigned int a, d;
	asm volatile("rdtsc" : "=a"(a), "=d"(d));
	return ((unsigned long) a) | (((unsigned long) d) << 32);
}


static inline unsigned long rdtscp(unsigned int *aux)
{
	unsigned int a, d, c;
	asm volatile("rdtscp" : "=a"(a), "=d"(d), "=c"(c));
	if (aux)
		*aux = c;
	return ((unsigned long) a) | (((unsigned long) d) << 32);
}

int main(int argc, char *argv[])
{
	struct timespec sleeptime = {.tv_nsec = 5E8 }; /* 1/2 second */
	struct timespec t_start, t_end;
	uint64_t cycles_per_us;

	cpu_serialize();
	if (clock_gettime(CLOCK_MONOTONIC_RAW, &t_start) == 0) {
		uint64_t ns, end, start;
		double secs;

		start = rdtsc();
		nanosleep(&sleeptime, NULL);
		clock_gettime(CLOCK_MONOTONIC_RAW, &t_end);
		end = rdtscp(NULL);
		ns = ((t_end.tv_sec - t_start.tv_sec) * 1E9);
		ns += (t_end.tv_nsec - t_start.tv_nsec);

		secs = (double)ns / 1000;
		cycles_per_us = (uint64_t)((end - start) / secs);
		printf("timer: detected %d ticks per US\n",
			 cycles_per_us);
		return 0;
	}

	return -1;
}